if (!global.KeyWasFull)
	global.KeyWasFull ={};
var kwf = global.KeyWasFull;

kwf.rounds=0;
function cpi(args) {
	var effecter = args.effecter; // the skill, item, or effect causing damage or healing.
	var skill = args.skill; // the effecter, if it is a skill
	var item = args.item; // the effecter, if it is an item
	var effect = args.effect; // the effecter, if it is an effect
	var unit = args.cur_unit; // the unit using the skill or item, if any
	var target = args.target_unit; // the target of the skill, item, or effect
	var targetTile = args.target_tile; // the tile being effected, if in TB combat
	var damage=effecter.ScriptFlags.get("current_percent_inflict")
	var h=makeHashFromPointString(damage);
	var x=0
	while (h[x]) {
		if (target){
			if(!target.Points.get(h[x][0])) {
				say(h[x][0]+" is not a valid point name in "+target.FriendlyName)
				return false
			}
			var pointMultiplier=(1-(h[x][1]/100));
			say("{0} loses {1} {2}".format(target.GetName(), ""+Math.ceil(target.Points.get(h[x][0]).Current*(h[x][1]/100)), h[x][0]));
			target.Points.get(h[x][0]).Current=target.Points.get(h[x][0]).Current*pointMultiplier
			shared.ShareUnitPointUpdate(target, [h[x][0]]);
		}
		x++;
	}
	return true
}
function kwf_on_map_key(args) {
	var key = args.k;
	var mod = args.m;

	if(key==q_key&&mod==shift_mod) {
		if(shared.Map.ScriptFlags.get("view_equipment")) {
if(shared.Map.ReviewTile.Selected) {
var s=shared.Map.ReviewTile.Selected;
var str=s.GetName()+" is wearing "
var j=s.GetEquippedItems();
if(j.length>0) {
for(var count=0; count<j.length; count++) {
str+=(count==j.length-1?"and ":"")+j[count].FriendlyName+(count<j.length-1?", ":"")+(count==j.length-1?".":"")
}
say(str)
}
}
}
}
	if(key==d_key&&mod==shift_mod) {
		if(shared.Map.ScriptFlags.get("key_for_ap")) {
			var u=shared.Map.AllUnits;
			say("The following zombies have 5 AP");
			var count=0
			for (var j=0; j<u.length; ++j) {
				if (u[j].Points.get("actions").Max==5&&u[j].Team==2) {
					++count;
				say(u[j].FriendlyType+" at "+shared.GetPos(u[j].Tile));
				}
			}
			if(count==0) say("none");
		}
	}

}
function makeHashFromPointString(pointString) {
    var commaSplit = pointString.split(",");
    var hash = {};

    for (var index = 0; index < commaSplit.length; index++) {
var pointValuePair = commaSplit[index];
//say(pointValuePair);
        var barSplit = pointValuePair.split("|");
        var pointName = barSplit[0];
        var pointValue = barSplit[1];
hash[index] =barSplit ;
    }
    return hash;
}

function kwf_after_item_equipped(e) {
	var unit = e.unit; // the unit that equipped the item
	var item = e.item; // the item equipped
	if(item.ScriptFlags.get("equip_sound")) {
		randomSound(item.ScriptFlags.get("equip_sound"))
	}
	if(item.ScriptFlags.get("equip_apply_effects")) {
		shared.ApplyEffect(item.ScriptFlags.get("equip_apply_effects"),unit);
	}
	if(item.ScriptFlags.get("equip_remove_effects")) {
		shared.RemoveEffect(item.ScriptFlags.get("equip_remove_effects"),unit);
	}
	if(item.ScriptFlags.get("equip_message")) {
		say(item.ScriptFlags.get("equip_message").format(unit.GetName(),item.FriendlyName));
	}
	if(item.ScriptFlags.get("equip_max_mod")) { 
		var maxmod=item.ScriptFlags.get("equip_max_mod");
		var h=makeHashFromPointString(maxmod)
		var x=0;
		while (h[x]) {
			if(!unit.Points.get(h[x][0])) {
				say(h[x][0]+" is not a valid point name in "+unit.FriendlyName)
				return false
			}
			unit.Points.get(h[x][0]).Max=unit.Points.get(h[x][0]).Max+parseInt(h[x][1]);
			if(!item.ScriptFlags.get("equip_lock_current_points")) {
				unit.Points.get(h[x][0]).Current=unit.Points.get(h[x][0]).Current+parseInt(h[x][1]);
			}
			shared.ShareUnitPointUpdate(unit, [h[x][0]]);
			x++;
		}
	}
}
function kwf_after_item_unequipped(e) {
    var unit = e.unit; // the unit that unequipped the item
    var item = e.item; // the item unequipped
var unequipMessage = (item.ScriptFlags.get("unequip_message"));
if (unequipMessage) {
var msg = chooseFromARandomSelectString(unequipMessage);
say(msg.format(unit.GetName(),item.FriendlyName));
}
	if(item.ScriptFlags.get("unequip_sound")) {
		randomSound(item.ScriptFlags.get("unequip_sound"))
	}
	if(item.ScriptFlags.get("equip_apply_effects")) {
		shared.RemoveEffect(item.ScriptFlags.get("equip_apply_effects"),unit);
	}

	if(item.ScriptFlags.get("equip_max_mod")) { 
		var maxmod=item.ScriptFlags.get("equip_max_mod");
		var h=makeHashFromPointString(maxmod)
		var x=0;
		while (h[x]) {
			if(!unit.Points.get(h[x][0])) {
				say(h[x][0]+" is not a valid point name in "+unit.FriendlyName)
				return false
			}
			unit.Points.get(h[x][0]).Max=unit.Points.get(h[x][0]).Max-parseInt(h[x][1]);
			if(!item.ScriptFlags.get("equip_lock_current_points")) {
				unit.Points.get(h[x][0]).Current=unit.Points.get(h[x][0]).Current-parseInt(h[x][1]);
			}
			shared.ShareUnitPointUpdate(unit, [h[x][0]]);
			x++;
		}
	}
}
function kwf_after_map_load(args) {
    var map = args.map;
	if(map.ScriptFlags.get("load_items")) {
loadItems(map.ScriptFlags.get("load_items"))
}
	if(map.ScriptFlags.get("start_tile")) {
		var g=map.ScriptFlags.get("start_tile")
		var h=g.split(" ")
		map.MoveReview(h[0]-1,h[1]-1)
	}
}
function kwf_after_create_unit(args) {
    var unit = args.unit;
var flags=unit.ScriptFlags;
	if (flags.get("random_stats")) {
		var max=flags.get("random_stats_max");
		var current=flags.get("random_stats_current");
		if (max) {
			h=makeHashFromPointString(max)
			var x=0;
			while (h[x]) {
				unit.Points.get(h[x][0]).Max=shared.Calculate(h[x][1]);
				if (unit.Points.get(h[x][0]).Current>unit.Points.get(h[x][0]).Max) {
					unit.Points.get(h[x][0]).Current=unit.Points.get(h[x][0]).Max
				}
				if(flags.get("random_stats_full_points")) {
					unit.Points.get(h[x][0]).Current=unit.Points.get(h[x][0]).Max
				}
				shared.ShareUnitPointUpdate(unit, [h[x][0]]);
				x++;
			}
		}
		}if (current) {
			h=makeHashFromPointString(current)
			var x=0;
			while (h[x]) {
				unit.Points.get(h[x][0]).Current=shared.Calculate(h[x][1]);
				if (unit.Points.get(h[x][0]).Current>unit.Points.get(h[x][0]).Max) {
				unit.Points.get(h[x][0]).Current=unit.Points.get(h[x][0]).Max
			}
			shared.ShareUnitPointUpdate(unit, [h[x][0]]);
			x++;
		}
	}

	else {
	}
if (flags.healthmanip) {
j=flags.healthmanip;
unit.Points.get("monster_health").Max+=parseInt(eval(j));
unit.Points.get("monster_health").Current=unit.Points.get("monster_health").Max;
}
if (flags.mvmanip) {
j=flags.mvmanip;
unit.Points.get("movement").Max+=parseInt(eval(j));
unit.Points.get("monster_health").Current=unit.Points.get("monster_health").Max;
}
}
function kwf_after_unit_death(args) {
    var unit = args.unit;
if(unit.ScriptFlags.get("death_splash_range")) {
deathSplash(args)
}
}//unit death

function deathSplash(args) {
    var unit = args.unit;
var affectedTiles=getCoordsWithinRange(unit.Tile,unit.ScriptFlags.get("death_splash_range"))
if(unit.ScriptFlags.get("death_splash_inflict")) {
var g=unit.ScriptFlags.get("death_splash_inflict");
var h=g.split(",")
for(var x=0; x<h.length; x++) {
h[x]=h[x].split("|");
}
for(var gg=0; gg<affectedTiles.length; gg++) {
if(affectedTiles[gg].Units.length>=1) {
for(var uCounter=0; uCounter<affectedTiles[gg].Units.length; uCounter++) {
for(var pointsCounter=0; pointsCounter<h.length; pointsCounter++) {
try {
if(affectedTiles[gg].Units[uCounter].Points.get(h[pointsCounter][0])) {
var randomUnit=shared.Map.AllUnits[0]
unit.DoDamageTo(affectedTiles[gg].Units[uCounter],h[pointsCounter][1],h[pointsCounter][0],h[pointsCounter][2])
}//if point exist
}
catch (err)
{
// nothing here, hopefully it skips over this and trys the next one
}

}//for point counter
}//for uCounter
}//units.length>1
if(affectedTiles[gg].Structures.length>=1) {
for(var sCounter=0; sCounter<affectedTiles[gg].Structures.length; sCounter++) {
for(var pointsCounter=0; pointsCounter<h.length; pointsCounter++) {
try {
if(affectedTiles[gg].Structures[sCounter].Points.get(h[pointsCounter][0])) {
unit.DoDamageTo(affectedTiles[gg].Structures[sCounter],h[pointsCounter][1],h[pointsCounter][0],h[pointsCounter][2])
}//if point exist
}
catch (err)
{
// nothing here, hopefully it skips over this and trys the next one
}
}//for point counter
}//for sCounter
}//structures.length>1
}//for affectedTiles
}//death splash inflict
if(unit.ScriptFlags.get("death_splash_effects")) {
var jj=unit.ScriptFlags.get("death_splash_effects")
jj=jj.split(",")
for(var b=0;b<jj.length;b++) {
var isTileEffect=vicDictionaryHasKey(shared.GetEffectObjectByName(jj[b]).AllFlags,"tile");
for(var gg=0; gg<affectedTiles.length; gg++) {
if(!isTileEffect&&affectedTiles[gg].Units.length>=1) {
for(var uCounter=0; uCounter<affectedTiles[gg].Units.length; uCounter++) {
shared.ApplyEffect(jj[b],affectedTiles[gg].Units[uCounter])
}//uCounter
}//units.length>=1
if(isTileEffect) {
shared.ApplyEffect(jj[b],null,affectedTiles[gg])
}//tileEffect
}//affected tiles
}//effects list
}//death splash effects
}//function
function vicDictionaryHasKey(dictionary, myKey)
{
var keys = dictionary.keys;
for (var i=0; i<keys.length; i++) {
if (keys[i] == myKey) return true;
}
return false;

}
function kwf_after_perform_skill(args) {
    var source = args.source_unit;
    var target = args.target_unit;
    var targetTile = args.target_tile;
    var skill = args.skill;
    var success = args.success; // indicates whether the skill was successful after the chance roll.
var flags=skill.ScriptFlags;
if (flags.get("randomize")) {
var how_many=flags.get("randomize_num_of_units");
var kind=flags.get("randomize_unit_type");
var rad_v=flags.get("randomize_radius_vertical");
var rad_h=flags.get("randomize_radius_horizontal");
var uteam=flags.get("randomize_unit_team");
if (!flags.get("randomize_num_of_units")) {
say("the randomize_num_of_units flag is needed.");
return;
}
else {
how_many=shared.Calculate(flags.get("randomize_num_of_units"));
if (!kind) {
say("You need to specify the type of unit to place.");
return;
}

if (!rad_v) {
rad_v=5;
}
if (!rad_h) {
rad_h=5;
}
if(flags.get("randomize_display_success")) {
say("placing "+how_many+" "+kind+"s, radius of "+rad_h+" horizontal and "+rad_v+" vertical.");
}
units_to_place=how_many;
while(units_to_place>0) 
{
units_to_place--;
u=shared.CreateUnit(kind);
if (!uteam) {
u.Team=source.Team;
}
else {
u.Team=uteam;
}
var cell=selectCell(args)
var safetyCount=0
while ((!cell||!canHold(cell.X,cell.Y,u))&&safetyCount<13) {
cell=selectCell(args);
safetyCount++;
}
shared.Map.AddUnit(u,cell.X,cell.Y);
}
}
}
else {
}
if(flags.get("effects_duration_mod")) {
var str=flags.get("effects_duration_mod");
split2=makeHashFromPointString(str);
//check effects on target, adjust their roundExpires as necessary. If roundExpires < shared.CurrentRound then make them equal
if(target&&target.Effects.length>0) {
for(var x=0; x<target.Effects.length; x++) {
for(var j=0; split2[j]; j++) {
if(target.Effects[x].ScriptFlags.get("permanent")) continue;
if(target.Effects[x].Name==split2[j][0]) {
target.Effects[x].RoundExpires=target.Effects[x].RoundExpires+parseInt(split2[j][1])
if(target.Effects[x].RoundExpires>=shared.Map.CurrentRound) say(target.Effects[x].Name+" will now fizzle in "+(target.Effects[x].RoundExpires-shared.Map.CurrentRound)+" rounds.")
if(target.Effects[x].RoundExpires<shared.Map.CurrentRound) shared.RemoveEffect(split2[j][0],target);
}//if
}//for
}//for
}//if//target effects
if(targetTile.Effects.length>0) {
for(var x=0; x<targetTile.Effects.length; x++) {
for(var j=0; split2[j]; j++) {
try {
if(targetTile.Effects[x].ScriptFlags.get("permanent")) continue;
if(targetTile.Effects[x].Name==split2[j][0]) {
targetTile.Effects[x].RoundExpires=targetTile.Effects[x].RoundExpires+parseInt(split2[j][1])
if(targetTile.Effects[x].RoundExpires>=shared.Map.CurrentRound) say(targetTile.Effects[x].Name+" will now fizzle in "+(targetTile.Effects[x].RoundExpires-shared.Map.CurrentRound)+" rounds.")
if(targetTile.Effects[x].RoundExpires<shared.Map.CurrentRound) shared.RemoveEffect(split2[j][0],target,targetTile);
}//if
}//try
catch(err) {
if(targetTile.Effects.length>0) {
for(var counter=0; counter<targetTile.Effects.length; counter++) {
say(targetTile.Effects[counter].Name)
}//for
}//if
}//catch
}//for
}
}//if tile effect
}//if

}//function
function kwf_after_use_item(args) {
    var source = args.source_unit;
    var target = args.target_unit;
    var targetTile = args.target_tile;
    var item = args.item;
    var success = args.success; // indicates whether the skill was successful after the chance roll.
}
function kwf_after_effect_applied(args) {
    var source = args.source_unit;
    var target = args.target_unit;
    var targetTile = args.target_tile;
    var effect = args.effect;
if(effect.ScriptFlags.get("permanent")) {
effect.RoundExpires=shared.Map.CurrentRound-5
}
if (effect.ScriptFlags.get("current_percent_inflict_mod")) {
source.pmod=effect.ScriptFlags.get("current_percent_inflict_mod")
}

}
function kwf_after_effect_removed(args) {
    var source = args.source_unit;
    var target = args.target_unit;
    var targetTile = args.target_tile;
    var effect = args.effect;
}
function kwf_after_effect_fizzled(args) {
    var target = args.target_unit;
    var tile = args.target_tile;
    var effect = args.effect;
}
function kwf_after_turn_ended(args) {
    var units = args.ending_units; // a list of units on the team that is ending their turn.
var x=0
if(units.length==0) return;
while(x<units.length) {
var j=0;
if(units[x].ScriptFlags.get("point_max_end_turn_mod")) {
pointsMaxEndTurnMod(units[x].ScriptFlags.get("point_max_end_turn_mod"),units[x]);
}//points max end turn mod
if(units[x].Effects.length>0) {
while(j<units[x].Effects.length) {
var p=units[x].Effects[j];
if(p.ScriptFlags.get("point_max_end_turn_mod")) {
pointsMaxEndTurnMod(p.ScriptFlags.get("point_max_end_turn_mod"),units[x]);
}
if(p.ScriptFlags.get("team_change_end_turn")) {
units[x].Team=p.ScriptFlags.get("team_change_end_turn");
}
j++
}//while
}//if
x++;
}//while
}//function
function kwf_after_turn_started(args) {
    var units = args.starting_units; // a list of units on the team that is starting their turn.
var x=0
if(units.length==0) return;
while(x<units.length) {
var j=0;
if(units[x].Effects.length>0) {
while(j<units[x].Effects.length) {
var p=units[x].Effects[j];
if(p.ScriptFlags.get("team_change_start_turn")) {
units[x].Team=p.ScriptFlags.get("team_change_start_turn");
}
j++
}//while
}//if
x++;
}//while
var changeMusic=shared.Map.ScriptFlags.get("change_music_at_round");
if(shared.Map.CurrentTurn==1) {
if (changeMusic) {
var h=makeHashFromPointString(changeMusic);
var x=0;
while(h[x]) {
if (shared.Map.CurrentRound==parseInt(h[x][0])) {
music(h[x][1]+".mp3");
}
x++;
}
}
return false;
}
}
function kwf_override_handle_causers(args) {
    // this function is responsible for dealing all damage and healing for any skill, item, or effect
    var effecter = args.effecter; // the skill, item, or effect causing damage or healing.
    var skill = args.skill; // the effecter, if it is a skill
    var item = args.item; // the effecter, if it is an item
    var effect = args.effect; // the effecter, if it is an effect
    var unit = args.cur_unit; // the unit using the skill or item, if any
    var target = args.target_unit; // the target of the skill, item, or effect
    var targetTile = args.target_tile; // the tile being effected, if in TB combat
var flags=effecter.ScriptFlags;
if (flags.get("current_percent_inflict")) {
return {handled: cpi(args)}
}
if (target&&target.ScriptFlags.get("reflects_damage_by")) {
//screw this shit really
//return {handled: damage_reflection(args)}
}
    return { handled: false }; // handled indicates this script decided to handle it and the engine should not do any further perform skill logic.
}
function damage_reflection(args) {
    var effecter = args.effecter; // the skill, item, or effect causing damage or healing.
    var skill = args.skill; // the effecter, if it is a skill
    var item = args.item; // the effecter, if it is an item
    var effect = args.effect; // the effecter, if it is an effect
    var unit = args.cur_unit; // the unit using the skill or item, if any
    var target = args.target_unit; // the target of the skill, item, or effect
    var targetTile = args.target_tile; // the tile being effected, if in TB combat
say("trying damage reflection.")
//figure pout what damage the target unit actually took. This disregards all protections on the target.
var h=makeHashFromPointString(target.ScriptFlags.get("reflects_damage_by"));
var x=0;
while(h[x]) {
//we look at the affecting skill and look for an inflict flag for this point. If we don't have it we continue.
if(skill) {
if(skill.AllFlags.get(h[x][0]+"_inflict")) {
//say(skill.Name);
var ff=skill.AllFlags.get(h[x][0]+"_inflict");
var commaSplit=ff.split(",")
ff={};
for(d=0; d<commaSplit.length; d++) {
var barSplit=commaSplit[d].split("|");
ff[d]=barSplit;
}

//ff[x][0] is the amount of damage, ff[x][1] is the damage type. If ff[x][1] does not exist we assume it is the default type.
var y=0;
while (ff[y]) {
say(ff[y][0]+" with damage type "+ff[y][1]);
y++;
}


}
}
x++;
}

}
function kwf_override_tb_team_ai(args) {
    var units = args.units; // the list of units that need their AI run.
    var friends = args.friends;
    var enemies = args.enemies;
for(var x=0; units[x]; x++) {
var unit=units[x];
if(unit.Team==3) {
    return { handled: true, did_something: false }
}
}

    return { handled: true }; // handled indicates this script decided to handle it and the engine should not do any further AI logic for this team.
}
function distanceFrom(unit1,unit2) {
return (Math.abs(unit2.X-unit1.X)+Math.abs(unit2.Y-unit1.Y));
}
function kwf_override_tb_unit_ai(args) {
    // This method will get called multiple times for each unit until all units report that they did not do anything.
    // If the override_tb_team_ai event is handled then this function will never get called as the team level AI supersedes this logic.
    var unit = args.unit; // the single unit that needs it's AI run.
    var friends = args.friends;
    var enemies = args.enemies;

    return { handled: false, did_something: true }; // handled indicates this script decided to handle it and the engine should not do any further AI logic for this unit.
    // did_something indicates whether this unit performed an action or not.
}

/*
function announce_point(e) {
	/// <summary>Reads out a specific point value of the selected unit</summary>
	/// <param name="e">The event object</param>	
	if (e.k != e.key || e.m != e.mod) {
		return; // it's not the key combination we are supposed to respond to.
	}
	var unit = shared.Map.ReviewTile.Selected;
	if (!unit) {
		say("no unit selected");
		return; // no unit so nothing to do
	}
	var pointName = e.Point;
	if (!pointName) {
		say("No point argument given to announce_point script.");
		return;
	}
	var output = e.Format;
	if (!output) {
		say("No Format argument given to announce_point script.");
		return;
	}
	if (!unit.Points.Get(pointName)) {
		say(unit.GetName() + " has no such point " + pointName);
		return;
	}
	var point = unit.Points.Get(pointName);
	if (output.indexOf("{0}") != -1) {
		output = output.replace("{0}", point.Current);
	}
	if (output.indexOf("{1}") != -1) {
		output = output.replace("{1}", point.Max);
	}
	say(output);
}

function cb_after_create_unit(e) {
	/// <summary>Runs after create logic on script flags (if any)</summary>
	/// <param name="e">The event object</param>
	if (!e.unit) {
		return; // we shouldn't get unitless after creates, but just in case
	}
	var unit = e.unit;
	var flags = unit.ScriptFlags;
	var transportCapacity = flags.get("transport_capacity");
	if (transportCapacity) {
		make_transport({ unit: unit, capacity: transportCapacity, onEnter: flags.get("on_enter_transport"), onExit: flags.get("on_exit_transport") });
	}
}

function cb_after_death(e) {
	/// <summary>Runs after death logic on script flags (if any)</summary>
	/// <param name="e">The event object</param>
	if (!e.unit) {
		return;
	}
	var unit = e.unit;
	var flags = unit.ScriptFlags;
	var death_message = flags.get("death_message");
	if (death_message) {
	    var msg = chooseFromARandomSelectString(death_message);
	    say(msg.format(unit.GetName()));
	}
	var unloads_transport_on_death = flags.get("unloads_cargo_on_death");
	if (unloads_transport_on_death) {
		unload_all_transported_units({ target: unit });
	}
	if (flags.get("death_transformation")) {
	    change_unit_type({ target: unit });
	}
}

function cb_after_perform_skill(e) {
    /// <summary>Handles after skill performed logic</summary>
	var source = e.source_unit;
	var target = e.target_unit;
	var tile = e.target_tile;
	var skill = e.skill;
	var success = e.success;
	var flags = skill.ScriptFlags;
	if (flags.get("enters_transport")) {
	    load_unit_into_transport({ source: source, target: target, skill: skill, success: success });
	}
	if (flags.get("unloads_transport")) {
		unload_all_transported_units({ source: source, target: target, tile: tile, skill: skill, success: success });
	}
	var adjusts_transport_capacity = flags.get("adjusts_transport_capacity");
	if (adjusts_transport_capacity) {
		adjust_transport_capacity({ target: target, adjustment: adjusts_transport_capacity });
	}
	if (flags.get("untoggle_team")) {
	    untoggle_team(target);
	}
	if (flags.get("revert_transformation")) {
	    var newUnit = revert_unit_type({ target: target, skill: skill, success: success });
	    if (newUnit)
	        target = newUnit; // so that subsequent stuff happens to the right unit
	}
	if (flags.get("transform_into")) {
	    var newUnit = change_unit_type({ source: source, target: target, skill: skill, success: success });
        if (newUnit)
	        target = newUnit; // so that subsequent stuff happens to the right unit
	}
	var hasToggleTeamFlag = flags.get("toggle_to_user_team") || flags.get("charm") || flags.get("toggle_to_team");
	if (hasToggleTeamFlag) {
	    toggle_team({ source: source, target: target, skill: skill, success: success });
	}
	if (flags.get("move_other_unit_away")) {
	    var tiles = flags.get("move_other_unit_away");
	    move_other_unit({ where: "away", source: source, target: target, tiles: tiles, skill: skill, success: success });
	}
	if (flags.get("move_other_unit_toward")) {
	    var tiles = flags.get("move_other_unit_toward");
	    move_other_unit({ where: "toward", source: source, target: target, tiles: tiles, skill: skill, success: success });
	}
	if (success && flags.get("success_message")) {
	    var msg = chooseFromARandomSelectString(flags.get("success_message"));
	    say(msg.format(source.GetName(), target.GetName()));
	}
	if (!success && flags.get("failure_message")) {
	    var msg = chooseFromARandomSelectString(flags.get("failure_message"));
	    say(msg.format(source.GetName(), target.GetName()));
	}
}

function cb_on_map_key(e) {
	/// <summary>Handles map key ppress logic</summary>
	var key = e.k;
    var mod = e.m;
	var map = shared.Map;
	var flags = map.ScriptFlags;
}

function cb_after_effect_applied(e) {
    var source = e.source_unit;
    var target = e.target_unit;
    var targetTile = e.target_tile;
    var effect = e.effect;
    var flags = effect.ScriptFlags;
    if (flags.get("transform_into") && target != null) {
        var newUnit = change_unit_type({ source: source, target: target, effect: effect });
        if (newUnit)
        target = newUnit;
    }
    var hasToggleTeamFlag = flags.get("toggle_to_user_team") || flags.get("charm") || flags.get("toggle_to_team");
    if (hasToggleTeamFlag) {
        toggle_team({ source: source, target: target, effect: effect });
    }
}

function cb_after_effect_removed(e) {
    var source = e.source_unit;
    var target = e.target_unit;
    var targetTile = e.target_tile;
    var effect = e.effect;
    var flags = effect.ScriptFlags;
    var hasToggleTeamFlag = flags.get("toggle_to_user_team") || flags.get("charm") || flags.get("toggle_to_team");
    if (hasToggleTeamFlag && target != null) {
        untoggle_team(target);
    }
    if (flags.get("transform_into") && target != null) {
        var newUnit = revert_unit_type({ target: target, effect: effect });
        if (newUnit)
            target = newUnit;
    }
}

function cb_after_effect_fizzled(e) {
    var target = e.target_unit;
    var tile = e.target_tile;
    var effect = e.effect;
    var flags = effect.ScriptFlags;
    var hasToggleTeamFlag = flags.get("toggle_to_user_team") || flags.get("charm") || flags.get("toggle_to_team");
    if (hasToggleTeamFlag && target != null) {
        untoggle_team(target);
    }
    if (flags.get("transform_into") && target != null) {
        var newUnit = revert_unit_type({ target: target, effect: effect });
        if (newUnit)
            target = newUnit;
    }
    var fizzleSound = flags.get("fizzle_sound");
    if (fizzleSound) {
        sound(fizzleSound);
    }
    var fizzleMessage = flags.get("fizzle_message");
    if (fizzleMessage) {
        var msg = chooseFromARandomSelectString(fizzleMessage);
        say(msg.format(target.GetName()));
    }
}

function cb_override_handle_causers(e) {
    var effecter = e.effecter;
    var skill = e.skill;
    var item = e.item;
    var effect = e.effect;
    var source = e.cur_unit;
    var target = e.target_unit;
    var targetTile = e.target_tile;
    var flags = effecter.ScriptFlags;
    if (flags.get("critical_hit_chance")) {
        var wasCritical = handleCritical(e);
        return { handled: wasCritical };
    }
    return { handled: false }; // handled indicates this script decided to handle it and the engine should not do any further perform skill logic.
}

// helper functions for internal use mostly

function calculateDirectionInt(sourceTile, targetTile) {
	if (sourceTile.Y == targetTile.Y) {
		if (sourceTile.X < targetTile.X) {
			return 6;
		} else if (sourceTile.X > targetTile.X) {
			return 2;
		} else { // they're on the same tile
			return; 
		}
	}
	else if (sourceTile.Y < targetTile.Y) {
		if (sourceTile.X == targetTile.X) {
			return 0;
		} else if (sourceTile.X > targetTile.X) {
			return 1;
		} else {
			return 7;
		}
	} else {
		if (sourceTile.X == targetTile.X) {
			return 4;
		} else if (sourceTile.X > targetTile.X) {
			return 3;
		} else {
			return 5;
		}	
	}
}

function getNextTileInDirection(currentTile, direction) {
	var x = currentTile.X, y = currentTile.Y;
	var mapWidth = shared.Map.Width - 1, mapHeight = shared.Map.Height - 1;
	switch (direction) {
		case 0:
			if (y > 0) {
				return shared.Map.GetTile(x, y - 1);
			} else {
				return currentTile;
			}
			break;
		case 1:
			if (x < mapWidth && y > 0) {
				return shared.Map.GetTile(x + 1, y - 1);
			} else {
				return currentTile;
			}
			break;
		case 2:
			if (x < mapWidth) {
				return shared.Map.GetTile(x + 1, y);
			} else {
				return currentTile;
			}
			break;
		case 3:
			if (x < mapWidth && y < mapHeight) {
				return shared.Map.GetTile(x + 1, y + 1);
			} else {
				return currentTile;
			}
			break;
		case 4:
			if (y < mapHeight) {
				return shared.Map.GetTile(x, y + 1);
			} else {
				return currentTile;
			}
			break;
		case 5:
			if (x > 0 && y < mapHeight) {
				return shared.Map.GetTile(x - 1, y + 1);
			} else {
				return currentTile;
			}
			break;
		case 6:
			if (x > 0) {
				return shared.Map.GetTile(x - 1, y);
			} else {
				return currentTile;
			}
			break;
		case 7:
			if (x > 0 && y > 0) {
				return shared.Map.GetTile(x - 1, y - 1);
			} else {
				return currentTile;
			}
			break;
		default:
			break;
	}
}

// not currently being used, but will be a nice thing to have working for code cleanup
// need to run tests after release is done
function getStandardEventProperties(event,argObject) {
	if (event.source_unit) {
		argObject.source_unit = event.source_unit;
	}
	if (event.target_unit) {
		argObject.target_unit = event.target_unit;
	}
	if (event.target_tile) {
		argObject.target_tile = event.target_tile;
	}
	if (event.unit) {
		argObject.unit = event.unit;
	}
	if (event.success) {
		argObject.success = event.success;
	}
}

function applyObjectToEvent(event, args, firstFormatArgument, secondFormatArgument) {
	for (var arg in args) {
		var argValue = args[arg];
		if (typeof argValue === 'string' && argValue.indexOf('{0}') != -1) {
			argValue = argValue.replace("{0}", firstFormatArgument);
		}
		if (typeof argValue === 'string' && argValue.indexOf('{1}') != -1) {
			argValue = argValue.replace("{1}", secondFormatArgument);
		}
		event[arg] = argValue;
	}
	return event;
}

function chooseFromARandomSelectString(original) {
    if (original.indexOf("|") == -1)
        return original;

    var choices = original.split('|');
    var randomIndex = Math.round(Math.random() * (choices.length - 1));
    var pick = choices[randomIndex];
    return pick;
}

// a version of String.Format found on StackOverflow
// First, checks if it isn't implemented yet.
if (!String.prototype.format) {
  String.prototype.format = function() {
    var args = arguments;
    return this.replace(/{(\d+)}/g, function(match, number) { 
      return typeof args[number] != 'undefined'
        ? args[number]
        : match;
    });
  };
}
*/
function selectCell(args) {
    var source = args.source_unit;
    var target = args.target_unit;
    var targetTile = args.target_tile;
    var skill = args.skill;
    var success = args.success; // indicates whether the skill was successful after the chance roll.
var flags=skill.ScriptFlags;
var rad_v=flags.get("randomize_radius_vertical");
var rad_h=flags.get("randomize_radius_horizontal");
var dx=shared.Calculate((targetTile.X-(Math.ceil(rad_h/2)))+"r"+(targetTile.X+(Math.ceil(rad_h/2))));
var dy=shared.Calculate((targetTile.Y-(Math.ceil(rad_v/2)))+"r"+(targetTile.Y+(Math.ceil(rad_v/2))));
if (dy>=shared.Map.Height) {
dy=shared.Map.Height-1;
}
if (dx>=shared.Map.Width) {
dx=shared.Map.Width-1;
}
//say(dx+", "+dy);
if (dx<0 ) {
dx=1;
}
if(dy<0) {
dy=1;
}
var cell=shared.Map.GetTile(dx,dy)
return cell;
}
function canHold(x, y, u) {
var tileTeam=44;
var cell=shared.Map.GetTile(x,y)
if(cell.Units.length>0) {

var tileTeam=cell.Units[0].Team;
}
if(tileTeam) {
if(cell.Structures.length>0) {
tileTeam=cell.Structures[0].Team;
}
}
if(tileTeam==44) {
tileTeam=-1
}
if(tileTeam==-1||u.Team==tileTeam) {
return cell.CanHold(u);
}
else return false;
}
function pointsMaxEndTurnMod(str,unit) {
//str=unit.ScriptFlags.get("point_max_end_turn_mod")
str=str.split(",")
for(var count=0; count<str.length; count++) {
str[count]=str[count].split("|")
//say(str[count][0])
var point=unit.Points.get(str[count][0]);
if(point) {
var hasPercent=false, hasLimit=false, work=true
if(str[count][2]) hasPercent=true
if(str[count][3]) hasLimit=true
if(hasPercent) {
var chance=str[count][2].substring(0,str[count][2].length-1)
if(chance<=0||chance>100) chance=100
//say(chance)
if(shared.Calculate("1r100")>chance) work=false
}//if has percent chance
if(hasLimit) {
var limit=str[count][3];
if(str[count][1][0]=="-") {
if(unit.Points.get(str[count][0]).Max<=limit) work=false;
}
else {
if(unit.Points.get(str[count][0]).Max>=limit) work=false;
}
}//limit
if(work) {
var increase=1;
if(str[count][1][0]=="-") {
increase=shared.Calculate(str[count][1].substring(1))
increase*=-1;
}
else {
increase=shared.Calculate(str[count][1])
}
//say(increase)
var increase_by=increase/(unit.Points.get(str[count][0]).Max==0?1:unit.Points.get(str[count][0]).Max)
unit.Points.get(str[count][0]).Max+=increase;
if(unit.Points.get(str[count][0]).Current==0) unit.Points.get(str[count][0]).Current+=increase_by
else unit.Points.get(str[count][0]).Current*=(1+increase_by);
}
			shared.ShareUnitPointUpdate(unit,[str[count][0]]);
}//if point

}//for count

}
function loadItems(str)
{
str=str.split(" ")
for(var x=0; x<str.length; x++) {
str[x]=str[x].split(",")
for(var y=0; y<str[x].length; y++) {
str[x][y]=str[x][y].split("=")
for(var z=0; z<str[x][y].length; z++) {
str[x][y][z]=str[x][y][z].split("|")
for(var p=0; p<str[x][y][z].length; p++) {
say(str[x][0][z][0])
}//p
}//z
}//y
}//x

}//function
function kwf_after_unit_move(e) {
    var unit = e.unit; // the unit that moved
    var added = e.unitAdded; // true if this unit was added to the map, false if it was just a movement
    var origin = e.origin; // the tile that this unit previously occupied. If added is true, this will be null
if(unit.Tile.Terrain.ScriptFlags.get("teleport_to")) {
if(!unit.IsFlying()||unit.Tile.Terrain.ScriptFlags.get("teleport_flying")) {
var tt=unit.Tile.Terrain.ScriptFlags.get("teleport_to")
tt=tt.split(",")
		shared.Map.MoveUnit(unit,tt[0]-1,tt[1]-1)
say("teleported to "+shared.GetPos(shared.Map.GetTile(tt[0]-1,tt[1]-1)));
shared.Map.MoveReview(tt[0]-1,tt[1]-1)
}//flying
}


}